#include <Globals.h>
#include <InterruptServiceRoutine.h>
#include <GenericFaultHandler.h>
#include <DescriptorTables.h>
#include <MonitorDriver.h>
#include <Asm.h>
#include <ProcessManager.h>

extern "C"
{
  u32int faultHandler(Registers r);
  u32int irqHandler(Registers r);
}

InterruptServiceRoutine::InterruptServiceRoutine()
{
}


InterruptServiceRoutine::~InterruptServiceRoutine()
{
}

void InterruptServiceRoutine::run(Registers *r)
{
}

//
// faultHandler -- Handles a software interrupt/CPU exception. This is architecture
//                 specific!
//
u32int faultHandler(Registers r)
{
  Address oldRegs = (Address)processManager->getProcess()->getRegistersPtr();
  processManager->getProcess()->setRegistersPtr(&r);
  InterruptServiceRoutine *isr = descriptorTables.getIsr(r.int_no);
  if (!isr)
  {
    isr = &genericHandler;
  }
  bool inKernel = processManager->getProcess()->isInKernel();
  processManager->getProcess()->setInKernel(true);

  s32int retVal = -1;
  isr->run(&r);
  
  processManager->getProcess()->setInKernel(inKernel);
  // If this process has an iopl of 3, tell the cpu!
  // set IOPL to 3 - 0b 00000000000000000011000000000000
  //              =  0x 0   0   0   0   3   0   0   0
  if(processManager->getProcess()->iopl == 3)
  {
    r.eflags |= 0x3000;     // if kernel or server, set IOPL to 3
  }
  else
  {
    r.eflags &= ~0x3000;    // else set it to 0 (unset it)
  }
  
  processManager->getProcess()->setRegistersPtr((Registers*)oldRegs);
//   kerr << "Returning eip = " << hex << (u32int)r.eip << endl;
  return 0;
}

//
// faultHandler -- Handles a software interrupt request. This is architecture
//                 specific!
//
u32int irqHandler(Registers r)
{
  InterruptServiceRoutine *isr = descriptorTables.getIsr(r.int_no);
  s32int retVal = -1;

  if (isr)
  {
    Address oldRegs = (Address)processManager->getProcess()->getRegistersPtr();
    processManager->getProcess()->setRegistersPtr(&r);
    isr->run(&r);

    processManager->getProcess()->setRegistersPtr((Registers*)oldRegs);
  }
  
  // If this process has an iopl of 3, tell the cpu!
  // set IOPL to 3 - 0b 00000000000000000011000000000000
  //              =  0x 0   0   0   0   3   0   0   0
  if(processManager->getProcess()->iopl == 3)
  {
    r.eflags |= 0x3000;     // if kernel or server, set IOPL to 3
  }
  else
  {
    r.eflags &= ~0x3000;    // else set it to 0 (unset it)
  }
//   kerr << "Returning eip(irq) = " << hex << (u32int)r.eip << endl;
  if (r.int_no >= 40)
  {
    // Send reset signal to slave.
    outb(0xA0, 0x20);
  }
  // Send reset signal to master. (As well as slave, if necessary).
  outb(0x20, 0x20);
  return retVal;
}
